﻿// ********************************
// 2010.10.16
// 设备信息抽象
// Author:卢融凯
// ********************************
using System;
using System.Collections.Generic;
using System.Linq;
using Lextm.SharpSnmpLib;
using Lextm.SharpSnmpLib.Messaging;
using SManage.LibExtension;
using SManage.Model;
using SManage.Infrastructure;
using System.Threading.Tasks;

namespace SManage.TraceEngine
{
    public class DeviceInfo
    {
        private SyncItem syncItem;

        public DeviceInfo(SyncItem item) {
            syncItem = item;
        }

        public Device Process() {

            var device = new Device();

            var systemTask      = Task.Factory.StartNew(() => GetMib2System(device));
            var interfacesTask  = Task.Factory.StartNew(() => GetMib2Interfaces(device));
            var ipTask          = Task.Factory.StartNew(() => GetMib2Ip(device));

            Task.WaitAll(systemTask, interfacesTask, ipTask);

            return device;
        }

        private Mib2_system GetMib2System(Device device) {
            String oidPrefix = ".1.3.6.1.2.1.1";
            //var variables = oidPrefix.ToOid().WalkFromSyncItem(syncItem);

            var system = new Mib2_system {
                sysDescr = GetData(oidPrefix + ".1.0").ToString(),
                sysObjectID = GetData(oidPrefix + ".2.0").ToString(),
                sysUpTime = GetData(oidPrefix + ".3.0").ToInt32(),
                sysContact = GetData(oidPrefix + ".4.0").ToString(),
                sysName = GetData(oidPrefix + ".5.0").ToString(),
                sysLocation = GetData(oidPrefix + ".6.0").ToString(),
                sysServices = GetData(oidPrefix + ".7.0").ToInt32(),
                Devices = device 
            };
            return system;
        }

        private Mib2_interfaces GetMib2Interfaces(Device device)
        {            
            var interfaces = new Mib2_interfaces() {
                ifNumber = ".1.3.6.1.2.1.2.1.0".ToOid().GetFromSyncItem(syncItem).First().Data.ToInt32()
            };

            var table = ".1.3.6.1.2.1.2.2.1".ToOid().WalkFromSyncItem(syncItem).ToTable(22);
            if (table == null) {
                return null;
            }
            Parallel.For(0, table.Count, i =>
            {
                var entity = new Mib2_interfaces_ifEntry { ifIndex = table[i][0].Data.ToInt32(), ifDescr = table[i][1].Data.ToString(), ifType = table[i][2].Data.ToInt32(), ifMtu = table[i][3].Data.ToInt32(), ifSpeed = table[i][4].Data.ToInt64(), ifPhysAddress = table[i][5].Data.ToString(), ifAdminStatus = table[i][6].Data.ToInt32(), ifOperStatus = table[i][7].Data.ToInt32(), ifLastChange = table[i][8].Data.ToInt32(), ifInOctets = table[i][9].Data.ToInt64(), ifInUcastPkts = table[i][10].Data.ToInt32(), ifInNUcastPkts = table[i][11].Data.ToInt32(), ifInDiscards = table[i][12].Data.ToInt32(), ifInErrors = table[i][13].Data.ToInt32(), ifInUnknownProtos = table[i][14].Data.ToInt32(), ifOutOctets = table[i][15].Data.ToInt64(), ifOutUcastPkts = table[i][16].Data.ToInt32(), ifOutNUcastPkts = table[i][17].Data.ToInt32(), ifOutDiscards = table[i][18].Data.ToInt32(), ifOutErrors = table[i][19].Data.ToInt32(), ifOutQLen = table[i][20].Data.ToInt64(), ifSpecific = table[i][21].Data.ToString(), Mib2_interfaces = interfaces };
                interfaces.Mib2_interfaces_ifEntry.Add(entity);
            });
            interfaces.Devices = device;
            return interfaces;
        }

        private Mib2_ip GetMib2Ip(Device device) {
            String oidPrefix = ".1.3.6.1.2.1.4";
            var ip = new Mib2_ip { ipForwarding = GetData(oidPrefix + ".1.0").ToInt32(), ipDefaultTTL = GetData(oidPrefix + ".2.0").ToInt32(), ipInReceives = GetData(oidPrefix + ".3.0").ToInt32(), ipInHdrErrors = GetData(oidPrefix + ".4.0").ToInt32(), ipInAddrErrors = GetData(oidPrefix + ".5.0").ToInt32(), ipForwDatagrams = GetData(oidPrefix + ".6.0").ToInt32(), ipInUnknownProtos = GetData(oidPrefix + ".7.0").ToInt32(), ipInDiscards = GetData(oidPrefix + ".8.0").ToInt32(), ipInDelivers = GetData(oidPrefix + ".9.0").ToInt32(), ipOutRequests = GetData(oidPrefix + ".10.0").ToInt32(), ipOutDiscards = GetData(oidPrefix + ".11.0").ToInt32(), ipOutNoRoutes = GetData(oidPrefix + ".12.0").ToInt32(), ipReasmTimeout = GetData(oidPrefix + ".13.0").ToInt32(), ipReasmReqds = GetData(oidPrefix + ".14.0").ToInt32(), ipReasmOKs = GetData(oidPrefix + ".15.0").ToInt32(), ipReasmFails = GetData(oidPrefix + ".16.0").ToInt32(), ipFragOKs = GetData(oidPrefix + ".17.0").ToInt32(), ipFragFails = GetData(oidPrefix + ".18.0").ToInt32(), ipFragCreates = GetData(oidPrefix + ".19.0").ToInt32(), ipRoutingDiscards = GetData(oidPrefix + ".23.0").ToInt32() };

            var ipAddrTask = Task.Factory.StartNew(() => GetIpAddrTable(ip));
            var ipRouteTask = Task.Factory.StartNew(() => GetIpRouteTable(ip));
            var ipNetToMediaTask = Task.Factory.StartNew(() => GetNetToMediaTable(ip));

            Task.WaitAll(ipAddrTask, ipRouteTask, ipNetToMediaTask);
            ip.Devices = device;
            return ip;
        }

        private void GetIpAddrTable(Mib2_ip ip) {
            var table = ".1.3.6.1.2.1.4.20.1".ToOid().WalkFromSyncItem(syncItem).ToTable(5);
            if (table == null || ip == null) {
                return;
            }
            Parallel.For(0, table.Count(), i =>
            {
                var ipAddrEntry = new Mib2_ip_ipAddrEntry { ipAdEntAddr = table[i][0].Data.ToString(), ipAdEntIndex = table[i][1].Data.ToInt32(), ipAdEntNetMask = table[i][2].Data.ToString(), ipAdEntBcastAddr = table[i][3].Data.ToInt32(), ipAdEntReasmMaxSize = table[i][4].Data.ToInt32(), Mib2_ip = ip };
                //ip.Mib2_ip_ipAddrEntry.Add(ipAddrEntry);
            });
        }

        private void GetIpRouteTable(Mib2_ip ip) {
            var table = ".1.3.6.1.2.1.4.21.1".ToOid().WalkFromSyncItem(syncItem).ToTable(13);
            if (table == null || ip == null) {
                return;
            }
            Parallel.For(0, table.Count(), i =>
            {
                var ipRouteEntry = new Mib2_ip_ipRouteEntry { ipRouteDest = table[i][0].Data.ToString(), ipRouteIfIndex = table[i][1].Data.ToInt32(), ipRouteMetric1 = table[i][2].Data.ToInt32(), ipRouteMetric2 = table[i][3].Data.ToInt32(), ipRouteMetric3 = table[i][4].Data.ToInt32(), ipRouteMetric4 = table[i][5].Data.ToInt32(), ipRouteNextHop = table[i][6].Data.ToString(), ipRouteType = table[i][7].Data.ToInt32(), ipRouteProto = table[i][8].Data.ToInt32(), ipRouteAge = table[i][9].Data.ToInt32(), ipRouteMask = table[i][10].Data.ToString(), ipRouteMetric5 = table[i][11].Data.ToInt32(), ipRouteInfo = table[i][12].Data.ToString(), Mib2_ip = ip };
                //ip.Mib2_ip_ipRouteEntry.Add(ipRouteEntry);
            });
        }

        private void GetNetToMediaTable(Mib2_ip ip) {
            var table = ".1.3.6.1.2.1.4.22.1".ToOid().WalkFromSyncItem(syncItem).ToTable(4);
            if (table == null || ip == null) {
                return;
            }
            Parallel.For(0, table.Count(), i =>
            {
                var ipNetToMediaEntry = new Mib2_ip_ipNetToMediaEntry { ipNetToMediaIfIndex = table[i][0].Data.ToInt32(), ipNetToMediaPhysAddress = table[i][1].Data.ToString(), ipNetToMediaNetAddress = table[i][2].Data.ToString(), ipNetToMediaType = table[i][3].Data.ToString(), Mib2_ip = ip };
                //ip.Mib2_ip_ipNetToMediaEntry.Add(ipNetToMediaEntry);
            });
        }

        private ISnmpData GetData(String oid) {
            var result = oid.ToOid().GetFromSyncItem(syncItem);
            return result.Count < 1 ? null : result.First().Data;
        }
     }
}
